package org.ponly.cta4j.factory.math;

import org.ponly.cta4j.drawing.Painter;
import org.ponly.cta4j.factory.AbstractCaptchaFactory;

import java.awt.image.BufferedImage;
import java.security.SecureRandom;
import java.util.Locale;
import java.util.Random;

/**
 * 数学计算验证码工厂.
 *
 * @author vacoor
 * @since 1.0
 */
public class MathFactory extends AbstractCaptchaFactory {
    /**
     * digits.
     */
    private static final int[] DIGITS = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

    /**
     * ten.
     */
    private static final int TEN = 10;

    /**
     * random for number length.
     */
    private final Random random = new SecureRandom();

    /**
     * number max length.
     */
    private int maxNumberLength = 2;

    /**
     * math operations.
     */
    private MathOperation[] mathOperations = new MathOperation[]{
            AbstractMathOperation.PLUS,
            AbstractMathOperation.MINUS
    };

    /**
     * 创建一个默认的数学计算验证码工厂.
     */
    public MathFactory() {
    }

    /**
     * 使用给定的 Painter 创建一个数学计算验证码工厂.
     *
     * @param painter Painter
     */
    public MathFactory(final Painter painter) {
        super(painter);
    }

    /**
     * 使用给定的 Painter 创建一个宽度高度为width, height的数学计算验证码工厂.
     *
     * @param width   验证码宽度
     * @param height  验证码高度
     * @param painter Painter
     */
    public MathFactory(final int width, final int height, final Painter painter) {
        super(width, height, painter);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public MathCaptcha getCaptcha() {
        return getCaptcha(null);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public MathCaptcha getCaptcha(final Locale locale) {
        final int maxNumberLength = getMaxNumberLength();
        int a;
        int b;
        MathOperation op;
        int value;
        do {
            a = getInteger(maxNumberLength);
            b = getInteger(maxNumberLength);
            op = getMathOperation();
        } while (0 > (value = op.eval(a, b)));

        final String text = String.valueOf(a) + op + b + "=?";
        final BufferedImage canvas = createCanvas();
        final Painter painter = getPainter();

        return new MathCaptcha(painter.paint(canvas, text), value);
    }

    /**
     * 随机获取一个数学运算符.
     *
     * @return 数学运算符
     */
    protected MathOperation getMathOperation() {
        return mathOperations[random.nextInt(mathOperations.length)];
    }

    /**
     * 随机获取一个整数.
     *
     * @param maxLen 整数最大长度.
     * @return 整数
     */
    protected int getInteger(final int maxLen) {
        int num;
        do {
            num = DIGITS[random.nextInt(DIGITS.length)];
        } while (1 > num);

        final int len = Math.max(0, random.nextInt(maxLen)) + 1;
        for (int i = 1; i < len; i++) {
            num = num * TEN + DIGITS[random.nextInt(DIGITS.length)];
        }
        return num;
    }

    /* ********************************
     *         GETTER / SETTER
     * ****************************** */

    /**
     * @return 允许的最大数字长度
     */
    public int getMaxNumberLength() {
        return maxNumberLength;
    }

    /**
     * 设置数字的最大长度.
     *
     * @param maxNumberLength 数字最大长度
     */
    public void setMaxNumberLength(final int maxNumberLength) {
        this.maxNumberLength = maxNumberLength;
    }
}
